﻿using Stee.CAP8.MessageBus.Interface.Models;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace Stee.CAP8.MessageBus.Sagas.Core.Sagas
{
    public class InMemorySagaStorage : ISagaStorage
    {
        private static ConcurrentDictionary<string, (CommandMessage,ISagaData)> _storageList = new ConcurrentDictionary<string, (CommandMessage, ISagaData)>();

        public Task Delete(CommandMessage message)
        {
            if (message is null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            var id = message.CorrelationID;

            return Task.FromResult(_storageList.TryRemove(id, out var _));

        }

      

        public Task<(CommandMessage, SagaData)> Find<SagaData>(string id) where SagaData : class,ISagaData
        {
            _storageList.TryGetValue(id, out var message);
           

            SagaData data  = ConvertSagaData<SagaData>(message.Item2);

            return Task.FromResult((message.Item1, data));
        }


       

        public Task Insert<SagaData>(CommandMessage message, ISagaData sagaData) where SagaData : class, ISagaData
        {
            if (message is null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            var id = message.CorrelationID;
            return Task.FromResult(_storageList.TryAdd(id, (message, sagaData)));
        }

      

        public Task Update<SagaData>(CommandMessage message, ISagaData sagaData) where SagaData : class, ISagaData
        {
            if (message is null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            var id = message.CorrelationID;
            return Task.FromResult(
            _storageList.AddOrUpdate(id, (message, sagaData), (k, v) =>
            {
                return v;
            }));
        }



        private static SagaData ConvertSagaData<SagaData>(ISagaData sagaData) where SagaData : class, ISagaData
        {
            if (sagaData == null) return null;
            SagaData data;
            try
            {
                data = (SagaData)sagaData;
            }
            catch (Exception ex)
            {

                throw new Exception($"SagaData不是{nameof(SagaData)}类型\n{ex.Message}");
            }

            return data;
        }
    }
}
